package core.agent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;

import core.api.offer.OfferConsumo;
import core.api.offer.OfferDefinition;
import core.datamodel.Element;
import core.datamodel.ElementValue;
import core.datamodel.Event;
import core.datamodel.Resource;
import core.tool.PropertyAccountit;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.util.Logger;


public class AgentController extends Agent {
	private Logger log = Logger.getJADELogger(this.getClass().getName());

	private AID[] calculators;
	private AID[] mgrInventory;
	private int counter = 1;
	boolean cancella = false;
	protected void setup() {

		// Register the controller service in the yellow pages
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(this.getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setType("Controller");
		sd.setName("Controller");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

		// Add a TickerBehaviour that schedules a request to  agents every minute
		addBehaviour(new TickerBehaviour(this, 10000) {

			protected void onTick() {
				System.out.println("Trying to send request ... numero "+ counter);

				// Update the list of controlleer agents
				DFAgentDescription template = new DFAgentDescription();
				ServiceDescription sd = new ServiceDescription();
				sd.setType("calculator");
				template.addServices(sd);
				try {
					DFAgentDescription[] result = DFService.search(myAgent, template); 
					System.out.println("Found the following calculator agents:");
					calculators = new AID[result.length];
					for (int i = 0; i < result.length; ++i) {
						calculators[i] = result[i].getName();
						log.info(calculators[i].getName());
					}


					// Update the list of controlleer agents
					template = new DFAgentDescription();
					sd = new ServiceDescription();
					sd.setType("manager-inventory");
					template.addServices(sd);

					result = DFService.search(myAgent, template); 
					log.info("Found the following Manager Inventory agents:");
					mgrInventory = new AID[result.length];
					for (int i = 0; i < result.length; ++i) {
						mgrInventory[i] = result[i].getName();
						log.info(mgrInventory[i].getName());

					}
				}
				catch (FIPAException fe) {
					fe.printStackTrace();
				}


				// Add the behaviour serving queries from buyer agents

				if (calculators.length>0 && mgrInventory.length>0) addBehaviour(new Tester());
				else log.info(" No calculator e/o  inventory agent disponibili");
			}
		}); // end ticker behaviur
	}

	// Put agent clean-up operations here
	protected void takeDown() {
		// Deregister from the yellow pages
		try {
			DFService.deregister(this);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

		System.out.println("Controller-agent "+getAID().getName()+" terminating.");
	}

	private class Tester extends Behaviour {
		int sequence = 0;
		private MessageTemplate mt;
		

		public void action() {
			System.out.println("Tester eseguo la richesta sequence:"+ sequence);
			switch(sequence){
			case 0:
				// costruisco la richiesta e la invio 

				ACLMessage req = new ACLMessage(ACLMessage.REQUEST);
				req.setReplyWith("account-data"+System.currentTimeMillis());

				ACLMessage reqToMgrInventory = new ACLMessage(ACLMessage.REQUEST);
				
				reqToMgrInventory.addUserDefinedParameter("TYPE",  "EVENT" );
			
				for (int i = 0; i < calculators.length; ++i) {
					req.addReceiver(calculators[i]);
				} 

				for (int i = 0; i < mgrInventory.length; ++i) {
					reqToMgrInventory.addReceiver(mgrInventory[i]);
				} 

				log.info("Prova del calculator");
				long step = 60 * 5;
				long stopTime= (new Date().getTime());
				long startTime= stopTime-step;
				req.addUserDefinedParameter("START_TIME",  new String().valueOf(startTime) );
				req.addUserDefinedParameter("STOP_TIME",  new String().valueOf(stopTime) );
				req.addUserDefinedParameter("STEP_TIME",  new String().valueOf(step) );
				req.setConversationId(new String().valueOf(counter));
				
				
				// costrisco l'oggetto resource
				
				
				Resource rsc = new Resource();
				rsc.setId(345);
				rsc.setExternalCustomerId("pluto");
				rsc.setExternalResourceId(999);
				rsc.setLocation("Torino");
				rsc.setOffer("CONSUMO");
				rsc.setCustomer("Customer");
				rsc.setService("Service");
				rsc.setResourceType("Vm");
				rsc.setResourceName("hostname");
				
				ArrayList <Element> elements = new ArrayList <Element>();
				Element ele = new Element();
				ele.setId(1);
				ele.setName("CPU");
				ele.setType("Integer");
				ele.setValue("100");
				elements.add( ele);
				rsc.setElements(elements);
				Event event = new Event();
				event.setEventResource(rsc);
				event.setAction("DELETE");
				
				try {
					req.setContentObject(rsc);
					reqToMgrInventory.setContentObject(event);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				myAgent.send(req);
				myAgent.send(reqToMgrInventory);

				log.info("OK Spedita richiesta n."+counter);
				counter++;
				// Prepare the template to get proposals
				mt = MessageTemplate.and(MessageTemplate.MatchPerformative(ACLMessage.PROPOSE),
						MessageTemplate.MatchInReplyTo(req.getReplyWith()));
				;
				sequence = 1;
				break;
			case 1:
				// Receive all proposals/refusals from seller agents
				ACLMessage reply = myAgent.receive(mt);

				if (reply != null) {
					System.out.println("Ricevuta la risposta");
					// Reply received
					if (reply.getPerformative() == ACLMessage.PROPOSE) {
						// This  e risposta
						ArrayList<ElementValue>  accounts = null;
						try {
							
							accounts = (ArrayList<ElementValue> ) reply.getContentObject();
						
						} catch (UnreadableException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
						
						// mando all'AgentInventory i dati di account
						ACLMessage sendAccount = new ACLMessage(ACLMessage.REQUEST);
						sendAccount.addUserDefinedParameter("TYPE",  "ACCOUNT" );
						for (int i = 0; i < mgrInventory.length; ++i) {
							sendAccount.addReceiver(mgrInventory[i]);
						} 
						
						try {
							sendAccount.setContentObject(accounts);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						log.info("Invio dati di account al DB");
						myAgent.send(sendAccount);
						


						sequence = 2;	
					}	
				}
				else {
					block();
				}
				break;
			} // end switch
		} 
		@Override
		public boolean done() {
			if (sequence==2) return true;
			return false;
		}


	}  // End of inner class OfferRequestsServer

}
